www.gusucode.com > 基于Visual C++高级界面特效制作百例源码程序 > 基于Visual C++高级界面特效制作百例源码程序/code/char13/gridctrllist/InPlaceEdit.cpp

    // InPlaceEdit.cpp : implementation file
//
// Written by Chris Maunder (Chris.Maunder@cbr.clw.csiro.au)
// Copyright (c) 1998.
//
// The code contained in this file is based on the original
// CInPlaceEdit from http://www.codeguru.com/listview/edit_subitems.shtml
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name is included. If 
// the source code in  this file is used in any commercial application 
// then acknowledgement must be made to the author of this file 
// (in whatever form you wish).
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
// Expect bugs!
// 
// Please use and enjoy. Please let me know of any bugs/mods/improvements 
// that you have found/implemented and I will fix/incorporate them into this
// file. 
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TCHAR.h"
#include "InPlaceEdit.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
 
/////////////////////////////////////////////////////////////////////////////
// CInPlaceEdit

CInPlaceEdit::CInPlaceEdit(CWnd* pParent, CRect& rect, DWORD dwStyle,
                           int nRow, int nColumn, CString sInitText, 
                           UINT nFirstChar)
{
    m_sInitText     = sInitText;
    m_nRow          = nRow;
    m_nColumn       = nColumn;
    m_nLastChar     = 0; 
    m_bExitOnArrows = (nFirstChar != VK_LBUTTON);    // If mouse click brought us here,
                                                     // then no exit on arrows

    DWORD dwEditStyle = WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|ES_MULTILINE | dwStyle;
    if (!Create(dwEditStyle, rect, pParent, IDC_IPEDIT)) return;

    SetFont(pParent->GetFont());

    SetWindowText(sInitText);
    SetFocus();

    switch (nFirstChar){
        case VK_LBUTTON: 
        case VK_RETURN:   SetSel((int)_tcslen(m_sInitText), -1); return;
        case VK_BACK:     SetSel((int)_tcslen(m_sInitText), -1); break;
        case VK_DOWN: 
        case VK_UP:   
        case VK_RIGHT:
        case VK_LEFT:  
        case VK_NEXT:  
        case VK_PRIOR: 
        case VK_HOME:  
        case VK_END:      SetSel(0,-1); return;
        default:          SetSel(0,-1);
    }

    SendMessage(WM_CHAR, nFirstChar);
}

CInPlaceEdit::~CInPlaceEdit()
{
}
 
BEGIN_MESSAGE_MAP(CInPlaceEdit, CEdit)
    //{{AFX_MSG_MAP(CInPlaceEdit)
    ON_WM_KILLFOCUS()
    ON_WM_NCDESTROY()
    ON_WM_CHAR()
    ON_WM_KEYDOWN()
    ON_WM_CREATE()
    ON_WM_KEYUP()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
////////////////////////////////////////////////////////////////////////////
// CInPlaceEdit message handlers

// If an arrow key (or associated) is pressed, then exit if
//  a) The Ctrl key was down, or
//  b) m_bExitOnArrows == TRUE
void CInPlaceEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
    if ((nChar == VK_PRIOR || nChar == VK_NEXT ||
         nChar == VK_DOWN  || nChar == VK_UP   ||
         nChar == VK_RIGHT || nChar == VK_LEFT) &&
        (m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0))
    {
        m_nLastChar = nChar;
        GetParent()->SetFocus();
        return;
    }

    if (nChar == VK_ESCAPE) 
    {
        SetWindowText(m_sInitText);    // restore previous text
        m_nLastChar = nChar;
        GetParent()->SetFocus();
        return;
    }

    CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
}

// Need to keep a lookout for Tabs, Esc and Returns. These send a 
// "KeyUp" message, but no "KeyDown". That's why I didn't put their
// code in OnKeyDown. (I will never understand windows...)
void CInPlaceEdit::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
    if (nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
    {
        m_nLastChar = nChar;
        GetParent()->SetFocus();    // This will destroy this window
        return;
    }

    CEdit::OnKeyUp(nChar, nRepCnt, nFlags);
}

// As soon as this edit loses focus, kill it.
void CInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
{
    CEdit::OnKillFocus(pNewWnd);
    EndEdit();
}

void CInPlaceEdit::EndEdit()
{
    CString str;
    GetWindowText(str);
 
    // Send Notification to parent (this was originally designed for listviews,
    // so we use listview structures and messages)

    LV_DISPINFO dispinfo;

    dispinfo.hdr.hwndFrom = GetParent()->GetSafeHwnd();
    dispinfo.hdr.idFrom   = GetDlgCtrlID();
    dispinfo.hdr.code     = LVN_ENDLABELEDIT;
 
    dispinfo.item.mask       = LVIF_TEXT|LVIF_PARAM;
    dispinfo.item.iItem      = m_nRow;
    dispinfo.item.iSubItem   = m_nColumn;
    dispinfo.item.pszText    = LPTSTR((LPCTSTR)str);
    dispinfo.item.cchTextMax = str.GetLength();
    dispinfo.item.lParam     = (LPARAM) m_nLastChar; 
 
    // Send a message to the parent of this edit's parent, telling the parent's parent
    // that the parent of this edit ctrl has recieved a LVN_ENDLABELEDIT message. 
    // Makes perfect sense, no? :)
    GetParent()->GetParent()->SendMessage(WM_NOTIFY, GetParent()->GetDlgCtrlID(), 
                                          (LPARAM)&dispinfo );
 
    DestroyWindow();
}
 
void CInPlaceEdit::OnNcDestroy()
{
    CEdit::OnNcDestroy();
    delete this;
}

void CInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
     CEdit::OnChar(nChar, nRepCnt, nFlags);
 
     // Resize edit control if needed
 
     // Get text extent
     CString str;
     GetWindowText( str );

     CWindowDC dc(this);
     CFont *pFontDC = dc.SelectObject(GetFont());
     CSize size = dc.GetTextExtent( str );
     dc.SelectObject( pFontDC );

     size.cx += 5;                   // add some extra buffer
 
     // Get client rect
     CRect rect, parentrect;
     GetClientRect( &rect );
     GetParent()->GetClientRect( &parentrect );
 
     // Transform rect to parent coordinates
     ClientToScreen( &rect );
     GetParent()->ScreenToClient( &rect );
 
     // Check whether control needs to be resized
     // and whether there is space to grow
     if (size.cx > rect.Width())
     {
         if( size.cx + rect.left < parentrect.right )
             rect.right = rect.left + size.cx;
         else
             rect.right = parentrect.right;
         MoveWindow( &rect );
     }
}